﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using NP.BPMReportPlatform.AnalysisInstance.Dtos;
using NP.BPMReportPlatform.DBHelper;
using NP.BPMReportPlatform.Entities.BPM_Business;
using NP.BPMReportPlatform.Entities.BPM_Business.FlowManage;
using NP.BPMReportPlatform.Entities.BPM_Business.ThirdFlow;
using NP.BPMReportPlatform.Entities.BPM_Engine;
using NP.BPMReportPlatform.Entities.BPM_Platform;
using NP.BPMReportPlatform.Entities.BPM_Process;
using NP.BPMReportPlatform.FlowManagement.Dto;
using NP.BPMReportPlatform.Reports.CommonApprovalProcessReport;
using NP.BPMReportPlatform.Reports.ThirdFlow.Dtos;
using NP.BPMReportPlatform.StandardApprovalFlow;
using NP.BPMReportPlatform.StandardApprovalFlow.Dto;
using NP.BPMReportPlatform.Utils;
using NP.Enterprise.Utils.Http;
using Renci.SshNet.Messages;
using Serilog;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Users;

namespace NP.BPMReportPlatform.Reports.ThirdFlow
{
    public class ThirdFlowCommonService : BPMReportPlatformAppService, IThirdFlowCommonService
    {
        private readonly SqlSugarClient _db, _dbPlatform, _dbProcess, _dbEngine, _dbToDoCenter;
        private readonly IBPMUtilsAppService _bPMUtilsApp;

        private readonly IConfiguration _configuration;
        private readonly INPRestHttpHelper _nPRestHttp;

        private readonly ILogger _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sqlSugarAppService"></param>
        public ThirdFlowCommonService(ISqlSugarAppService sqlSugarAppService, IBPMUtilsAppService bPMUtilsApp,
            IConfiguration configuration, INPRestHttpHelper nPRestHttp, ILogger logger)
        {
            _db = sqlSugarAppService.GetBusinessInstance();
            _dbPlatform = sqlSugarAppService.GetPlatformInstance();
            _bPMUtilsApp = bPMUtilsApp;
            _dbProcess = sqlSugarAppService.GetProcessInstance();
            _dbEngine = sqlSugarAppService.GetEngineInstance();
            _dbToDoCenter = sqlSugarAppService.GetToDoCenterInstance();

            _configuration = configuration;
            _nPRestHttp = nPRestHttp;
            _logger = logger;
        }

        /// <summary>
        /// 查询数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<GetThirdFlowCommonOutput>> GetAllAsync(GetThirdFlowCommonInput input)
        {
            RefAsync<int> totalCount = 0;

            var defaultDate = DateTime.Now.AddDays(-60);

            var currentUserId = Guid.Empty;
            if (!input.IsQueryAll)
            {
                var currentUserDto = _dbPlatform.Queryable<Users>().Where(x => x.WorkNumber.Equals(CurrentUser.UserName)).First();
                if (currentUserDto != null)
                {
                    currentUserId = currentUserDto.UserId;
                }
            }
            var listViewDto = await _dbEngine.Queryable<Instances, InstanceStates>((i, ins) =>
                new JoinQueryInfos(JoinType.Inner, i.InstanceId == ins.InstanceId))
                   .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), i => i.Number.Contains(input.InstanceNumber))
                   .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), i => i.StartUserName.Equals(input.AddUserName))
                   .WhereIF(!input.IsQueryAll, i => i.StartUserId.Equals(currentUserId))
                   .WhereIF(!input.BTID.IsNullOrEmpty(), i => SqlFunc.ContainsArray<string>(input.BTID, i.BTID))
                   .WhereIF(!string.IsNullOrWhiteSpace(input.FlowType), i => i.BTID.Equals(input.FlowType))
                   .WhereIF(input.StartCreationTime == null && string.IsNullOrWhiteSpace(input.InstanceNumber) && string.IsNullOrWhiteSpace(input.Topic), (i, ins) => ins.StartTime >= defaultDate)
                   .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null, (i, ins) => ins.StartTime >= input.StartCreationTime && ins.StartTime <= input.EndCreationTime)
                   .WhereIF(!string.IsNullOrWhiteSpace(input.Topic), i => i.Topic.Contains(input.Topic)).Select((i, ins) =>
                   new GetThirdFlowCommonOutput()
                   {
                       InstanceId = i.InstanceId,
                       InstanceNumber = i.Number,
                       Topic = i.Topic,
                       StartUserName = i.StartUserName,
                       StartTime = ins.StartTime,
                       LatestActivityName = ins.LatestActivityName,
                       Status = ins.Status,
                       StatusName = ins.StatusName,
                   }).MergeTable().OrderBy(ins => ins.StartTime, OrderByType.Desc)
                .ToPageListAsync(input.PageIndex, input.PageSize, totalCount);

            var instanceIds = listViewDto.Select(x => x.InstanceId);

            var activityDatas = await _dbEngine.Queryable<Activities, Tasks>((a, b) =>
                new JoinQueryInfos(JoinType.Left, a.ActivityId.ToString() == b.ActivityId))
                .Where(a => instanceIds.Contains(a.InstanceId) && a.Status == 1)
                .Select((a, b) => new ActivitieTaskModel
                {
                    InstanceId = a.InstanceId,
                    InstanceNumber = a.InstanceNumber,
                    Name = a.Name,
                    ArriveTime = a.ArriveTime,
                    ElapsedTime = a.ElapsedTime,
                    FinishTime = a.FinishTime,
                    UserId = b.UserId,
                    UserName = b.UserName,
                    GrandNodeId = a.GrandNodeId,
                }).ToListAsync();

            var userDto = await _dbPlatform.Queryable<Users>().Where(x => x.WorkNumber.Equals(CurrentUser.UserName)).SingleAsync();

            listViewDto.ForEach(x =>
            {
                x.Url = _bPMUtilsApp.GetProcessUrl(x.InstanceNumber, userDto.UserId.ToString());
                var activityData = activityDatas.Where(q => x.InstanceId.Equals(q.InstanceId));
                x.ActivityResolverName = string.Join(";", activityData.Select(q => q.UserName).Distinct());
            });

            //返回结果
            return new PagedResultDto<GetThirdFlowCommonOutput>()
            {
                TotalCount = totalCount,
                Items = listViewDto
            };
        }

        /// <summary>
        /// 导出数据
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<List<GetThirdFlowCommonOutput>> ExportAsync(GetThirdFlowCommonInput input)
        {
            var defaultDate = DateTime.Now.AddDays(-60);

            var currentUserId = Guid.Empty;

            var listQueryable = _dbEngine.Queryable<Instances, InstanceStates, Activities, Tasks>((i, ins, a, t) =>
                new JoinQueryInfos(JoinType.Inner, i.InstanceId == ins.InstanceId,
                JoinType.Left, i.InstanceId == a.InstanceId && a.Status == 1,
                JoinType.Left, a.ActivityId.ToString() == t.ActivityId))
                   .WhereIF(!string.IsNullOrWhiteSpace(input.InstanceNumber), i => i.Number.Contains(input.InstanceNumber))
                   .WhereIF(!string.IsNullOrWhiteSpace(input.AddUserName), i => i.StartUserName.Equals(input.AddUserName))
                   .WhereIF(!input.IsQueryAll, i => i.StartUserId.Equals(currentUserId))
                   .WhereIF(!input.BTID.IsNullOrEmpty(), i => SqlFunc.ContainsArray<string>(input.BTID, i.BTID))
                   .WhereIF(!string.IsNullOrWhiteSpace(input.FlowType), i => i.BTID.Equals(input.FlowType))
                   .WhereIF(input.StartCreationTime != null && input.EndCreationTime != null, (i, ins) => ins.StartTime >= input.StartCreationTime && ins.StartTime <= input.EndCreationTime)
                   .WhereIF(string.IsNullOrEmpty(input.FlowType) && (input.BTID == null || !input.BTID.Any()), (i, ins) => ins.StartTime >= defaultDate)
                   .WhereIF(!string.IsNullOrWhiteSpace(input.Topic), i => i.Topic.Contains(input.Topic)).Select((i, ins, a, t) =>
                   new GetThirdFlowCommonOutput()
                   {
                       InstanceId = i.InstanceId,
                       InstanceNumber = i.Number,
                       Topic = i.Topic,
                       StartUserName = i.StartUserName,
                       StartTime = ins.StartTime,
                       LatestActivityName = ins.LatestActivityName,
                       Status = ins.Status,
                       StatusName = ins.StatusName,
                       ActivityId = a.ActivityId,
                       ActivityResolverName = t.UserName,
                   }).MergeTable()
                   .GroupBy(x => x.InstanceId)
                   .Select(x => new GetThirdFlowCommonOutput
                   {
                       InstanceId = x.InstanceId,
                       InstanceNumber = x.InstanceNumber,
                       Topic = x.Topic,
                       StartUserName = x.StartUserName,
                       StartTime = x.StartTime,
                       LatestActivityName = x.LatestActivityName,
                       Status = x.Status,
                       StatusName = x.StatusName,
                       ActivityId = x.ActivityId,
                       ActivityResolverName = CommonSqlFuncExtension.CustomFieldSelect("GROUP_CONCAT(DISTINCT ActivityResolverName)")
                   });
            var listViewDto = await listQueryable.ToListAsync();
            return listViewDto;
        }

        public async Task<string> ThirdFlowCallBack(ThirdFlowCallBakInput input)
        {
            if (string.IsNullOrEmpty(input.InstanceNumber))
            {
                throw new Exception("缺少入参：InstanceNumber");
            }

            var approveEmploye = await _dbPlatform.Queryable<Users>().FirstAsync(x => x.UserId == input.ApproveEmployeeId);
            if (approveEmploye == null)
            {
                throw new Exception("审批人信息未找到");
            }

            var instance = await _dbEngine.Queryable<Instances>().FirstAsync(x => x.Number == input.InstanceNumber);
            if (instance == null)
            {
                throw new Exception("未找到Instances表数据");
            }

            var instanceState = await _dbEngine.Queryable<InstanceStates>().FirstAsync(x => x.InstanceId == instance.InstanceId);
            if (instanceState == null)
            {
                throw new Exception("未找到InstanceStates表数据");
            }

            var instanceParams = await _dbEngine.Queryable<InstanceParams>().Where(x => x.InstanceId == instance.InstanceId).ToListAsync();
            if (!instanceParams.Any())
            {
                throw new Exception("未找到InstanceParams表数据");
            }

            var callBackStr = instanceParams.FirstOrDefault(x => x.Key == "callBack")?.Value;
            if (string.IsNullOrEmpty(callBackStr))
            {
                throw new Exception("未找到callBack对象数据");
            }
            var callBackDto = JsonConvert.DeserializeObject<ThirdFlowCallBackDto>(callBackStr);

            var process = await _dbProcess.Queryable<ProcessResponsible>().FirstAsync(x => x.ProcessId == instance.ProcessId);
            if (process == null)
            {
                throw new Exception("未找到ProcessResponsible表数据");
            }

            var dics = new Dictionary<string, object>();
            instanceParams.ForEach(param =>
            {
                try
                {
                    var json = JsonConvert.DeserializeObject(param.Value);
                    dics.Add(param.Key, json);
                }
                catch
                {
                    dics.Add(param.Key, param.Value);
                }
            });

            var tables = string.Empty;
            if (process.FormType != "ThirdPagingTableLogic")
            {
                tables = dics.ContainsKey("tables") ? JsonConvert.SerializeObject(dics["tables"]) : "";
            }

            var flowStatus = (callBackDto.Type == 2 || callBackDto.Type == 4) ?
                (input.ApproveStatus == "refused" ? "1" : "2") // 审批通过传1，拒绝传2
                : input.flowStatus;

            if ((callBackDto.Type == 1 || callBackDto.Type == 3) && string.IsNullOrEmpty(input.flowStatus))
            {
                if (input.ApproveStatus == "approved")
                {
                    var lastRecord = await _dbEngine.Queryable<Records>().Where(
                        x => x.InstanceNumber == input.InstanceNumber && x.ResolveType == instanceState.Status)
                        .OrderBy(x => x.OperateTime, OrderByType.Desc).FirstAsync();
                    flowStatus = lastRecord != null && lastRecord.ActivityName == input.ApproveStepName &&
                        lastRecord.ResolveUserId == input.ApproveEmployeeId.ToString() ? "1" : "0"; // 如果是最后一个审批人，且审批通过，且流程已结束，传1
                }
                else
                {
                    flowStatus = "1"; //拒绝，不用判断是否是最后一个审批，固定传1
                }
            }

            var sendData = new
            {
                BTID = instance.BTID,
                InstanceNumber = instance.Number,
                FlowStatus = flowStatus,
                ApproveStepStatus = input.ApproveStatus,
                ApproveStepStatusName = input.ApproveStatus == "approved" ? "同意" : "拒绝",
                ApproveStepName = input.ApproveStepName,
                ApproveEmployeeCode = approveEmploye.WorkNumber,
                ApproveEmployeeName = approveEmploye.UserName,
                Comment = input.Comment,
                Forms = dics.ContainsKey("forms") ? JsonConvert.SerializeObject(dics["forms"]) : "",
                Tables = tables,
                CallBack = new
                {
                    ESBUrl = callBackDto.ESBUrl,
                    ServiceName = callBackDto.ServiceName,
                    Type = callBackDto.Type,
                    SAPINTERFACENAME = callBackDto.SAPINTERFACENAME,
                },
                SystemVariables = dics.ContainsKey("systemVariables") ? dics["systemVariables"] : new List<string>(),
            };
            var host = _configuration["BPM:ThirdBusinessApiUrl"];//"https://localhost:44321/";// 
            var url = process.FormType == "ThirdPagingTableLogic" ?
                $"{host}ThirdFlow/PagingTableCallbackBeforeApprovalStepApproval" :
                $"{host}ThirdFlow/CallbackBeforeApprovalStepApproval";

            var result = await _nPRestHttp.PostAsync(url, sendData);

            if (string.IsNullOrEmpty(result))
            {
                return "执行成功";
            }

            var res = JsonConvert.DeserializeObject<ThirdFlowResult>(result);

            if (res.Code == 200)
            {
                return "执行成功";
            }
            else
            {
                throw new Exception(res.Message);
            }
        }

        /// <summary>
        /// 流程作废
        /// </summary>
        /// <param name="instanceNumber"></param>
        /// <returns></returns>
        public async Task<string> ThirdFlowCancel(ThidFlowOpreaterInput input)
        {
            var rst = await _nPRestHttp.PostAsync($"{_configuration["BPM:ThirdBusinessApiUrl"]}ThirdFlow/Cancel", input);

            if (string.IsNullOrEmpty(rst))
            {
                return "作废成功";
            }

            var res = JsonConvert.DeserializeObject<ThirdFlowResult>(rst);

            if (res.Code == 200)
            {
                try
                {
                    var businessesInfo = await _db.Queryable<BusinessProcessesNew>().FirstAsync(x => x.InstanceId == input.InstanceNumber && x.ProcessStatusCode == "approved");
                    if (businessesInfo != null)
                    {
                        businessesInfo.ProcessStatusCode = "canceled";
                        businessesInfo.ProcessStatusName = "已终止";
                        await _db.Updateable(businessesInfo).ExecuteCommandAsync();
                    }

                    // 记录日志
                    var history = new InstanceOperateHistory
                    {
                        Id = Guid.NewGuid(),
                        InstanceNumber = input.InstanceNumber,
                        CreateTime = DateTime.Now,
                        Creator = CurrentUser.UserName,
                        InstanceCategory = 2,
                        OpearteType = 1,
                        Result = rst,
                        InputParam = JsonConvert.SerializeObject(input),
                    };

                    _logger.Information(JsonConvert.SerializeObject(history));

                    await _db.Insertable(history).ExecuteCommandAsync();
                }
                catch (Exception ex)
                {
                    _logger.Error($"{JsonConvert.SerializeObject(input)}：{ex.Message}");

                    return $"流程已作废，但是发生异常：{ex.Message}";
                }

                return "作废成功";
            }
            else
            {
                throw new Exception(res.Message);
            }
        }

        /// <summary>
        /// 流程撤回
        /// </summary>
        /// <param name="instanceNumber"></param>
        /// <returns></returns>
        public async Task<string> ThirdFlowRecall(ThidFlowOpreaterInput input)
        {
            var rst = await _nPRestHttp.PostAsync($"{_configuration["BPM:ThirdBusinessApiUrl"]}ThirdFlow/Recall", input);

            if (string.IsNullOrEmpty(rst))
            {
                return "撤回成功";
            }

            var res = JsonConvert.DeserializeObject<ThirdFlowResult>(rst);

            if (res.Code == 200)
            {
                return "撤回成功";
            }
            else
            {
                throw new Exception(res.Message);
            }
        }
    }
}
